
#include "StdAfx.h"
#include "StaticProcessInfo.h"
#include "NumericTime.h"

#include "ShareMemory.h"

#ifdef WIN32

#ifdef _UNICODE
#define tcout	wcout
#else
#define tcout	cout
#endif

LONG TopExceptionFilter( LPEXCEPTION_POINTERS pExp );

typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
					 CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
					 CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
					 CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);

LONG TopExceptionFilter( LPEXCEPTION_POINTERS pExp ){
	StaticProcessInfo::Instance()->callExceptionHandler( 0 );

	char szFullName[ MAX_PATH ];
	memset( szFullName, 0, MAX_PATH );

	char* szName = StaticProcessInfo::Instance()->getName();
	strncpy( szFullName, szName, MAX_PATH );
	strncpy( (char*)&(szFullName[ strlen( szName ) ]), ".dmp", MAX_PATH - strlen( szName ) );

	LONG retval = EXCEPTION_CONTINUE_SEARCH;
	HMODULE hDll = NULL;
	hDll = ::LoadLibrary(_T("DBGHELP.DLL"));

	if(! hDll )
		return retval;

	MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );

	if(! pDump )
		return retval;

	HANDLE hFile = ::CreateFile(_T( szFullName ), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
					FILE_ATTRIBUTE_NORMAL, NULL);

	if(INVALID_HANDLE_VALUE != hFile){
		_MINIDUMP_EXCEPTION_INFORMATION ExInfo;

		ExInfo.ThreadId = ::GetCurrentThreadId();
		ExInfo.ExceptionPointers = pExp;
		ExInfo.ClientPointers = NULL;

		BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL );
		if( bOK )
			retval = EXCEPTION_EXECUTE_HANDLER;		

		::CloseHandle( hFile );
	}

	::FreeLibrary( hDll );

	return retval;
}

#endif

StaticProcessInfo::StaticProcessInfo( char* name ){
	func_ = 0;
	start_sec_ = 0;

	if(! name )
		strncpy( uniq_name_, "noname", DEF_STR_TMP );
	else
		strncpy( uniq_name_, name, DEF_STR_TMP );

#ifdef WIN32
	SetUnhandledExceptionFilter( (LPTOP_LEVEL_EXCEPTION_FILTER)TopExceptionFilter );
#endif

#ifdef WIN32
	data_ = new WinShareMemory< SharedNames >();
#endif

#ifdef LINUX
	data_ = new UnixShareMemory< SharedNames >();
#endif
	
	int result = data_->create( DEF_SAHRED_MEMORY_NAME_COUNT, DEF_SHARED_NAME.c_str() );

	if( result == ShareMemory<SharedNames>::DEF_SHM_CREATE_FAIL ){
		std::cout << "fail shared memory names = " << DEF_SHARED_NAME.c_str() << std::endl;		
		return;
	}

	if( result == ShareMemory<SharedNames>::DEF_SHM_CREATE_ALREADY ){
		std::cout << "already exist shared memory names = " << DEF_SHARED_NAME.c_str() <<std::endl;		
		return;
	}	

	std::cout << "create shared memory names = " << DEF_SHARED_NAME.c_str() <<std::endl;	
}

StaticProcessInfo::~StaticProcessInfo(){
}

StaticProcessInfo* StaticProcessInfo::Instance( char* name ){
	if(! StaticProcessInfo_ )
		StaticProcessInfo_ = new StaticProcessInfo( name );
	
	return StaticProcessInfo_;
}

void StaticProcessInfo::Shutdown(){
	if( StaticProcessInfo_ ){
		delete StaticProcessInfo_;
		StaticProcessInfo_ = 0;
	}	
}

void StaticProcessInfo::start(){
	start_sec_ = (int)time( 0 );

	std::cout << "** app name is " <<uniq_name_ <<std::endl;
	std::cout << "  - start sec is " <<start_sec_ <<std::endl;	
	std::cout << "  - today is " <<NumericTime::getCurrentYear() <<"-" \
		<<NumericTime::getCurrentMonth() <<"-" \
		<<NumericTime::getCurrentDay() <<" " \
		<<NumericTime::getCurrentHour() <<":" \
		<<NumericTime::getCurrentMin() <<":" \
		<<NumericTime::getCurrentSec() <<std::endl;

	std::string exception = "";
	if( func_ )
		exception = "exist";
	else
		exception = "none";

	std::cout << "  - exception handler " <<exception.c_str() <<std::endl;

	std::cout << "  - notice!!!" <<std::endl;
	for( size_t i = 0 ; i < notice_.size() ; i++ ){
		std::cout << "    " << ( i + 1 ) <<" : " <<notice_[ i ].c_str() <<std::endl;
	}
}

void StaticProcessInfo::register_msg( char* msg ){
	notice_.push_back( msg );
}

int StaticProcessInfo::runtime_sec(){
	return (int)( time( 0 ) - start_sec_ );
}

char* StaticProcessInfo::getName(){
	return uniq_name_;
}

void StaticProcessInfo::setExceptionHandler( int (*func)( void* ), char* name ){
	func_ = func;

	if(! name )
		return;

	if(! strncmp( uniq_name_, "noname", strlen( name ) ) )
		strncpy( uniq_name_, name, DEF_STR_TMP );
}

void StaticProcessInfo::callExceptionHandler( void* data ){
	if( func_ )
		func_( data );
}

void StaticProcessInfo::register_shared_name( char* name, int type ){
	if(! name )
		return;

	if( strlen( name ) >= DEF_SHARED_MEMORY_NAME_LEN )
		return;

	SharedNames* data = 0;

	for( size_t i = 0 ; i < DEF_SAHRED_MEMORY_NAME_COUNT ; i++ ){
		data = data_->get( i );

		if(! data )
			continue;

		if( data->reg_time )
			continue;

		data->reg_time = (int)time( 0 );
		data->type = type;
		strncpy( data->names, name, DEF_SHARED_MEMORY_NAME_LEN );

		std::cout << "registerd share mem name = " << name <<std::endl;

		break;
	}
}
